﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

using Perseus;
using Perseus.Data;
using Perseus.Plugins;
using Perseus.Windows;

using Hetymine.Executioner.Commands;
using Hetymine.Executioner.Data;

/**
 * TODO:
 * - Show favicons and app icons for websites and application commands
 */
namespace Hetymine.Executioner.Plugins.General.CommandBox {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class CommandBox : Window, IPlugin, IExecutable, ILoader, IConfigurable<IniFile> {
        #region Private Fields
        private CommandBoxConfigurator _Configurator;
        
        private bool _TaskbarMode; // Show executioner window in taskbar

        // History / Autocomplete
        private int _HistoryIndex; // Current history item index to display (-1 = current, -2 blank)
        private List<string> _AutoComplete; // Array of possible autocomplete values
        private int _AutoCompleteIndex; // Current index of autocomplete list
        private bool _NoAutoCompleteUpdate; // When true, editing text field does not update autocomplete
        private string _CurrentCommand; // Currently typed command that hasnt been executed
        private bool _NoInputUpdate; // When true, input text changed event is ignored               

        private bool _NoOffsetUpdate;
        private Point _Offset;
        #endregion
        #region Initialization
        public CommandBox() {
            InitializeComponent();            
            this.PluginInfo = PluginInfo.FromAssembly(
                "Command Box",
                this.GetType().Assembly,
                "Blake Hancock",
                "http://hetymine.com/executioner/plugins/general/commandbox/"
            );

            this.SizeChanged += new SizeChangedEventHandler(CommandBox_SizeChanged);
            this.LocationChanged += new EventHandler(CommandBox_LocationChanged);
            this.Closing += new System.ComponentModel.CancelEventHandler(CommandBox_Closing);

            this.Deactivated += new EventHandler(CommandBox_Deactivated);
            this.StateChanged += new EventHandler(CommandBox_StateChanged);

            // Add key handlers for catching enter and command history
            this.cCommand.PreviewKeyDown += new KeyEventHandler(Command_PreviewKeyDown);
            this.cCommand.PreviewKeyUp += new KeyEventHandler(Command_PreviewKeyUp);            
            this.cCommand.TextChanged += new TextChangedEventHandler(Command_TextChanged);
            this.cCommand.SelectionChanged += new RoutedEventHandler(Command_SelectionChanged);
        }

        private void CommandBox_SizeChanged(object sender, SizeChangedEventArgs e) {            
            this.UpdatePosition();
        }
        private void CommandBox_LocationChanged(object sender, EventArgs e) {
            // Keep track of the temporary left and top offset when the user moves the command window
            if (this.IsLoaded && !this._NoOffsetUpdate) {
                Point p = this.CurrentPosition();
                this._Offset = new Point(this.Left - p.X, this.Top - p.Y);
            }
        }
        private void CommandBox_Closing(object sender, CancelEventArgs e) {
            e.Cancel = true;
            this.Hide();
        }
        #endregion
        #region Show and Hide
        public new void Show() {
            this._Offset = new Point(0, 0);

            this._NoInputUpdate = true;
            this.cCommand.Text = string.Empty;
            this._NoInputUpdate = false;

            if (this._CurrentCommand.IsEmpty()) {
                this._HistoryIndex = -1;
            }
            else { // Unentered command, but we still want it cleared on show
                this._HistoryIndex = -2;
            }

            this.ResetAutoComplete();            

            this.WindowState = WindowState.Normal;
            this.Visibility = Visibility.Visible;

            // Reset the width in case it was expanded before positioning
            this.cCommand.Width = Math.Max(200, Executioner.Config.GetInt("Command Box", "Width", 300));
            this.cCommand.Width = double.NaN;
            this.UpdatePosition();
            
            this.Activate();
            this.cCommand.Focus();       
        }
        public new void Hide() {
            if (this._TaskbarMode) {
                this.WindowState = WindowState.Minimized;
            }
            else {
                this.Visibility = Visibility.Hidden;
            }
        }
        private void CommandBox_Deactivated(object sender, EventArgs e) {
            if (!this._TaskbarMode) {
                this.Hide();
            }
        }
        private void CommandBox_StateChanged(object sender, EventArgs e) {
            if (this._TaskbarMode && this.WindowState == WindowState.Normal) {
                this.Show();
            }
        }
        #endregion
        #region Command Box
        private void Command_PreviewKeyDown(object sender, KeyEventArgs e) {
            // Only allow alt key if opening system menu.
            if (Keyboard.Modifiers == (Keyboard.Modifiers | ModifierKeys.Alt)) {
                if (e.Key == Key.System && Keyboard.IsKeyDown(Key.Space)) {
                    return;
                }
                
                e.Handled = true;                
                return;
            }

            this._NoInputUpdate = true;
            switch (e.Key) {
                case Key.Enter: // Execute command!            
                    if (Keyboard.Modifiers == ModifierKeys.Control) {
                        e.Handled = this.DoKeyEnterNewline();
                    }
                    else {
                        e.Handled = this.DoKeyEnter(
                            Keyboard.Modifiers == ModifierKeys.Shift,
                            Keyboard.Modifiers == (ModifierKeys.Control | ModifierKeys.Shift)
                        );
                    }
                    break;
                case Key.Tab: // Tab through parameters
                    // Select single parameter
                    if (Keyboard.Modifiers == (Keyboard.Modifiers | ModifierKeys.Control)) {
                        e.Handled = this.DoKeyTabSingle();                        
                    }
                    else { // Select remaining parameter
                        e.Handled = this.DoKeyTabAll();
                    }
                    break;
                case Key.Space: // Activate autocomplete
                    e.Handled = this.DoKeySpace();
                    break;
                case Key.Down: // Next command
                    e.Handled = this.DoKeyDown();
                    break;
                case Key.Up: // Previous command
                    e.Handled = this.DoKeyUp();
                    break;
                case Key.Escape: // Hide window on escape
                    this.Hide();
                    break;
                case Key.Delete:
                    this._NoAutoCompleteUpdate = true;
                    break;
                case Key.Back:
                    if (this.cCommand.SelectionStart > 0) {
                        this._NoAutoCompleteUpdate = true;
                        // If there is an auto complete value, then we need to
                        // selected one character more since only selection is
                        // deleted on backspace
                        if (this._AutoComplete.Count > 0) {
                            this.cCommand.SelectionStart = this.cCommand.SelectionStart - 1;
                            ++this.cCommand.SelectionLength;
                        }
                    }
                    break;
                case Key.C:
                    // Copy entire command, not just selected portions
                    if (Keyboard.Modifiers == (ModifierKeys.Control | ModifierKeys.Shift)) {
                        Clipboard.SetText(this.cCommand.Text);
                        e.Handled = true;
                    }
                    break;
                case Key.V:
                    // Same as shift + enter
                    if (Keyboard.Modifiers == (ModifierKeys.Control | ModifierKeys.Shift)) {
                        this.DoKeyEnter(true, false);
                        e.Handled = true;
                    }
                    break;
            }
            this._NoInputUpdate = false;
        }
        private void Command_PreviewKeyUp(object sender, KeyEventArgs e) {
            // Prevnets system menu from being activated when alt hotkey brings focus to window
            e.Handled = true;
        }
        private bool DoKeyEnterNewline() {
            int start = this.cCommand.SelectionStart;
            int length = this.cCommand.SelectionLength;

            string text = this.cCommand.Text.Substring(0, start) +
                          Environment.NewLine +
                          this.cCommand.Text.Substring(start + length);

            this.cCommand.Text = text;
            this.cCommand.SelectionStart = start + Environment.NewLine.Length;

            this.UpdateAutoComplete();
            return true;
        }
        private bool DoKeyEnter(bool appendClipboard, bool removeSelected) {
            string cmd;
            if (removeSelected && this.cCommand.SelectionLength > 0) {
                cmd = this.cCommand.Text.Substring(0, this.cCommand.SelectionStart) +
                    this.cCommand.Text.Substring(this.cCommand.SelectionStart + this.cCommand.SelectionLength);
            }
            else {
                cmd = this.cCommand.Text;
            }

            if (appendClipboard) {
                // If there is a space and text selected, it is a history value 
                // Override to make shift enter replace old value with new
                int space = cmd.IndexOf(" ", StringComparison.Ordinal);
                if (space > 0 && cCommand.SelectionLength > 0) {
                    cmd = cmd.Substring(0, space);
                }
                cmd += " " + Clipboard.GetText();
            }
            cmd = cmd.Trim();

            this._CurrentCommand = string.Empty;

            if (!cmd.IsEmpty()) {
                if (cmd == Executioner.Config.GetString("Command Box", "Call String", "cmdbox")) {
                    this.Show();
                }
                else {
                    this.Hide();

                    string command;
                    string arguments;

                    // If the command starts with a quote, assume it's in the form: "command" arguments
                    if (cmd.StartsWith("\"", StringComparison.Ordinal)) {
                        command = cmd;
                        arguments = string.Empty;
                    }
                    else {
                        command = "@execute";
                        arguments = cmd;
                    }

                    if (!Executioner.ExecuteCommand(command, arguments)) {
                        string defaultCommand = Executioner.Config.GetString("Command Box", "Default Command");
                        if (!defaultCommand.IsEmpty()) {
                            // If the command was not found, sent it as an argument to the defualt command
                            if (Executioner.ExecuteCommand("@execute", defaultCommand + " " + cmd, false)) {
                                Executioner.History.Add(cmd);
                            }
                            else {
                                // Set the failed command to the current command in case a mistake was made so they can easily fix it.
                                this._CurrentCommand = cmd;
                            }
                        }
                        else {
                            this._CurrentCommand = cmd;
                        }
                    }
                }
            }
            else {
                this.Hide();
            }

            return true;
        }
        private bool DoKeyTabSingle() {
            int length = this.cCommand.Text.Length;

            if (length == 0) {
                return true;
            }

            int start = this.cCommand.SelectionStart;
            string text = this.cCommand.Text;
            int pos1;
            int pos2;            

            if (Keyboard.Modifiers == (Keyboard.Modifiers | ModifierKeys.Shift)) {
                if (start == 0) {
                    pos1 = 0;
                    pos2 = 0;
                }
                else {
                    if (start == length) {
                        pos1 = text.LastIndexOf(" ", start);                        
                    }
                    else if (start - 1 == 0) {                        
                        pos1 = 0;                        
                    }
                    else {
                        pos1 = text.LastIndexOf(" ", start - 2);
                    }

                    if (pos1 <= 0) {
                        pos1 = 0;
                    }
                    else {
                        ++pos1;
                    }

                    pos2 = this.cCommand.Text.IndexOf(" ", pos1);
                    if (pos2 < 0) {
                        pos2 = length;
                    }
                }

                this.cCommand.Select(pos1, pos2 - pos1);
            }
            else {
                if (start == length) {
                    pos1 = start;
                    pos2 = length;
                }
                else {
                    // Special case if user presses say g then a space, we want the first tabbed item to still be the item
                    // directly after the space instead of the next, we check if the selected portion of a string contains a 
                    // space so that it doesn't get stuck on one selected item
                    if (start == 0) {
                        if (this.cCommand.SelectedText.Contains(" ") ||
                            this.cCommand.SelectionLength == 0 ||
                            (this.cCommand.SelectionLength != length && text.Substring(this.cCommand.SelectionLength, 1).IsNot(" "))
                        ) {
                            pos1 = start;
                        }
                        else {
                            pos1 = -1;
                        }
                    }
                    else if (
                        text.Substring(start - 1, 1).Is(" ") && 
                        (
                            this.cCommand.SelectedText.Contains(" ") || 
                            (
                                start + this.cCommand.SelectionLength != length &&
                                text.Substring(start + this.cCommand.SelectionLength, 1).IsNot(" ")
                            )
                        )
                    ) {
                        pos1 = start;
                    }
                    else {
                        pos1 = -1;                        
                    }

                    if (pos1 < 0) {
                        pos1 = text.IndexOf(" ", start);
                        if (pos1 < 0) {
                            pos1 = length;
                        }
                        else {
                            ++pos1;
                        }
                    }

                    if (pos1 == length) {
                        pos2 = length;
                    }
                    else {
                        pos2 = this.cCommand.Text.IndexOf(" ", pos1);
                        if (pos2 < 0) {
                            pos2 = length;
                        }
                    }
                }

                this.cCommand.Select(pos1, pos2 - pos1);                
            }

            return true;
        }
        private bool DoKeyTabAll() {
            if (this.cCommand.Text.Length == 0) {
                return true;
            }

            int start = this.cCommand.SelectionStart;
            int pos;
            
            // Update auto complete when tabbing through parameters while 
            // maintaining the same auto complete value
            if (this._AutoComplete.Count > 0) {
                // Should be an emptry string so no action needed
                if (this._AutoCompleteIndex == -1) {
                    return true;
                }

                string currentCommand = this.cCommand.Text;
                string newCommand;

                if (Keyboard.Modifiers == (Keyboard.Modifiers | ModifierKeys.Shift)) {
                    if (start > 0) {
                        start -= 1;
                    }

                    pos = this.cCommand.Text.LastIndexOf(" ", start);
                    if (pos >= 0) {
                        newCommand = this.cCommand.Text.Substring(0, pos);
                    }
                    else { // The very beginning
                        newCommand = string.Empty;
                    }
                }
                else {
                    if (start < this.cCommand.Text.Length) {
                        start += 1;
                    }

                    pos = this.cCommand.Text.IndexOf(" ", start);
                    if (pos >= 0) {
                        newCommand = this.cCommand.Text.Substring(0, pos);
                    }
                    else { // End of the line
                        newCommand = this.cCommand.Text;
                    }
                }

                this.cCommand.Text = newCommand;
                this.UpdateAutoComplete(currentCommand);
            }
            // Just update the selection since no auto complete
            else {
                if (Keyboard.Modifiers == (Keyboard.Modifiers | ModifierKeys.Shift)) {
                    if (start > 0) {
                        start -= 1;
                    }

                    pos = this.cCommand.Text.LastIndexOf(" ", start);
                    if (pos >= 0) {
                        this.SelectText(pos);
                    }
                    else { // The very beginning
                        this.SelectText(0);
                    }
                }
                else {
                    if (start < this.cCommand.Text.Length) {
                        start += 1;
                    }

                    pos = this.cCommand.Text.IndexOf(" ", start);
                    if (pos >= 0) {
                        this.SelectText(pos);
                    }
                    else { // End of the line
                        this.SelectText(this.cCommand.Text.Length);
                    }
                }    
            }

            return true;
        }
        private bool DoKeySpace() {
            if (Keyboard.Modifiers == ModifierKeys.Control) {
                this.UpdateAutoComplete();

                return true;
            }

            return false;
        }
        private bool DoKeyDown() {
            if (this.cCommand.Text.IndexOf(Environment.NewLine) >= 0 &&
                        Keyboard.Modifiers != ModifierKeys.Control
                    ) {
                // Let normal action take place
                return false;
            }

            if (this._AutoComplete.Count > 1) {
                this.AutoCompleteDown();
            }
            // If only one item left, set to current command and continue normally
            else if (this._AutoComplete.Count == 1) {
                this.ResetAutoComplete();
                this._HistoryIndex = -1;
                this.cCommand.Text = this._CurrentCommand;
                this.HistoryDown();
            }
            else {
                this.HistoryDown();
            }

            return true;
        }
        private bool DoKeyUp() {
            if (this.cCommand.Text.IndexOf(Environment.NewLine) >= 0 &&
                        Keyboard.Modifiers != ModifierKeys.Control
                    ) {
                // Let normal action take place
                return false;
            }

            if (this._AutoComplete.Count > 1) {
                this.AutoCompleteUp();
            }
            else if (this._AutoComplete.Count == 1) {
                this.ResetAutoComplete();
                this._HistoryIndex = -1;
                this.HistoryUp();
            }
            else {
                this.HistoryUp();
            }

            return true;
        }

        private void Command_TextChanged(object sender, TextChangedEventArgs e) {
            // If not in preview key down
            if (this._NoInputUpdate) {
                return;
            }

            this.UpdateAutoComplete();
        }        
        private void Command_SelectionChanged(object sender, RoutedEventArgs e) {            
            if (!this._NoInputUpdate) {
                // If not selecting to end of text, clear auto complete
                if (this.cCommand.SelectionStart + this.cCommand.SelectionLength != cCommand.Text.Length) {
                    this.ResetAutoComplete();
                }
                else {
                    foreach (string s in this._AutoComplete) {
                        if (s.Length < this.cCommand.SelectionStart) {
                            this.ResetAutoComplete();
                            break;
                        }
                    }
                }
            }
        }

        private void SelectText(int index) {
            int length = this.cCommand.Text.Length - index;
            if (length < 0) {
                this.cCommand.Select(this.cCommand.Text.Length, 0);
            }
            else {
                this.cCommand.Select(index, length);
            }
        }

        private void HistoryUp() {
            if (this._HistoryIndex == -2) {
                this._HistoryIndex = -1;
                this.cCommand.Text = this._CurrentCommand;
            }
            else if (this._HistoryIndex < Executioner.History.Count - 1) {
                if (this._HistoryIndex == -1) {
                    this._CurrentCommand = this.cCommand.Text;
                }
                ++this._HistoryIndex;
                this.cCommand.Text = Executioner.History[this._HistoryIndex];
            }
            else {
                System.Media.SystemSounds.Beep.Play();
                return;
            }

            this.cCommand.SelectionStart = this.cCommand.Text.Length;
        }
        private void HistoryDown() {
            // There is a new command typed but not executed and has been cleared
            if (this._HistoryIndex == -2) {
                System.Media.SystemSounds.Beep.Play();
                return;
            }
            else if (this._HistoryIndex == -1) { // Current command index
                // If the current command is not blank, then to blank index (-2)
                if (!this.cCommand.Text.IsEmpty()) {
                    this._HistoryIndex = -2;
                    this._CurrentCommand = this.cCommand.Text;
                    this.cCommand.Text = string.Empty;
                }
                else {
                    System.Media.SystemSounds.Beep.Play();
                    return;
                }
            }
            else if (this._HistoryIndex == 0) { // Set to current command empty or not
                this._HistoryIndex = -1;
                this.cCommand.Text = this._CurrentCommand;
            }
            else {
                --this._HistoryIndex;
                this.cCommand.Text = Executioner.History[this._HistoryIndex];
            }

            this.cCommand.SelectionStart = this.cCommand.Text.Length;
        }
        private void AutoCompleteUp() {
            if (this._AutoCompleteIndex == -1) {
                ++this._AutoCompleteIndex;
                int index = this._CurrentCommand.Length;
                this.cCommand.Text = this._AutoComplete[this._AutoCompleteIndex];
                this.SelectText(index);
            }
            else if (this._AutoCompleteIndex < this._AutoComplete.Count - 1) {
                ++this._AutoCompleteIndex;
                int index = this.cCommand.SelectionStart;
                this.cCommand.Text = this._AutoComplete[this._AutoCompleteIndex];
                this.SelectText(index);
            }
            else {
                System.Media.SystemSounds.Beep.Play();
            }
        }
        private void AutoCompleteDown() {
            if (this._AutoCompleteIndex == -1) {
                System.Media.SystemSounds.Beep.Play();
            }
            else if (this._AutoCompleteIndex == 0) {
                --this._AutoCompleteIndex;
                this._CurrentCommand = this.cCommand.Text.Substring(0, this.cCommand.SelectionStart);
                this.cCommand.Text = string.Empty;
            }
            else {
                --this._AutoCompleteIndex;
                int index = this.cCommand.SelectionStart;
                this.cCommand.Text = this._AutoComplete[this._AutoCompleteIndex];
                this.SelectText(index);
            }
        }
        private void UpdateAutoComplete() {
            this.UpdateAutoComplete(string.Empty);
        }
        private void UpdateAutoComplete(string autoComplete) {
            this._HistoryIndex = -1;
            this._CurrentCommand = this.cCommand.Text;

            this.ResetAutoComplete();

            // Prevents auto complete from being updated
            // such as when the backspace or delete key are pressed
            if (this._NoAutoCompleteUpdate) {
                this._NoAutoCompleteUpdate = false;
                return;
            }

            if (this.cCommand.Text.IsNotEmpty()) {
                // Get names of all string commands and history
                var names = from h in Executioner.History
                            where h.StartsWith(this.cCommand.Text, StringComparison.Ordinal)
                            select h;

                var cmds = from c in Executioner.CallStrings
                           where c.StartsWith(this.cCommand.Text, StringComparison.Ordinal) && c != "-clear"
                           select c;

                names = names.Union(cmds).OrderBy(p => p);

                foreach (string name in names) {
                    this._AutoComplete.Add(name);
                }

                // Enable auto complete selection if matching items exist
                if (this._AutoComplete.Count > 0) {
                    string s = this.cCommand.Text;
                    bool inputUpdate = this._NoInputUpdate;
                    this._NoInputUpdate = true;
                    this.cCommand.Text = this._AutoComplete[0];
                    // If autocomplete is set, select the old item if it exists
                    if (autoComplete.IsNotEmpty()) {
                        for (int i = 0; i < this._AutoComplete.Count; ++i) {
                            if (this._AutoComplete[i].Is(autoComplete)) {
                                this.cCommand.Text = this._AutoComplete[i];
                                this._AutoCompleteIndex = i;
                            }
                        }
                    }
                    this.cCommand.Select(s.Length, this.cCommand.Text.Length - s.Length);
                    this._NoInputUpdate = inputUpdate;
                }
            }
            else if (autoComplete.IsNotEmpty()) {
                this._AutoComplete.Add(autoComplete);
                bool inputUpdate = this._NoInputUpdate;
                this._NoInputUpdate = true;
                this.cCommand.Text = autoComplete;
                this.cCommand.Select(0, this.cCommand.Text.Length);
                this._NoInputUpdate = inputUpdate;
            }
        }
        private void ResetAutoComplete() {
            this._AutoComplete = new List<string>();
            this._AutoCompleteIndex = 0;
        }
        #endregion

        private void UpdatePosition() {
            Point p = this.CurrentPosition();
            
            p.X += this._Offset.X;
            p.Y += this._Offset.Y;

            this._NoOffsetUpdate = true;
            this.Left = p.X;
            this.Top = p.Y;
            this._NoOffsetUpdate = false;
        }
        private Point CurrentPosition() {
            int display = Executioner.Config.GetInt("Command Box", "Display", -1);
            string alignment = Executioner.Config.GetString("Command Box", "Alignment", "centre centre");
            double left = Executioner.Config.GetInt("Command Box", "Left", 0);
            double top = Executioner.Config.GetInt("Command Box", "Top", 0);

            Point p = Display.Position(display, alignment, left, top, this.ActualWidth, this.ActualHeight);

            return p;
        }

        private ImageSource FavIcon(string requestUrl) {
            string hash = PCrypt.MD5(requestUrl);
            string file = Executioner.CacheDirectory + hash + ".ico";
            if (File.Exists(file)) {
                BitmapImage bi = new BitmapImage(new Uri(file, UriKind.Absolute));
                return bi;
            }

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl);
            request.UserAgent = Executioner.Config.GetString("Executioner", "User Agent", Executioner.VersionString);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            StreamReader sr = new StreamReader(response.GetResponseStream());
            string source = sr.ReadToEnd();
            sr.Close();

            int start = 0;
            while (true) {
                int pos = source.IndexOf("<link ", start);
                if (pos == -1) {
                    break;
                }


            }

            return null;
        }

        #region IPlugin
        public PluginInfo PluginInfo { get; protected set; }
        #endregion

        #region IExecutable
        public List<string> CallStrings { get; set; }

        public ExecutionResult Execute(string parameters) {            
            this.Show();
            return ExecutionResult.Success;            
        }
        #endregion
        #region ILoader
        public void Load() {
            // The window offset when the command box is dragged to a different position
            this._NoOffsetUpdate = false;
            this._Offset =  new Point(0, 0);

            // Disable return so keydown will detect up and down keys
            this.cCommand.AcceptsReturn = false;
            this.cCommand.AcceptsTab = false;

            this.cCommand.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
            this.cCommand.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;

            // Set command input and auto complete values to their defaults
            this.cCommand.Text = string.Empty;
            this._CurrentCommand = string.Empty;
            this._HistoryIndex = -1;
            this._NoInputUpdate = false;

            this.ResetAutoComplete();
            this._NoAutoCompleteUpdate = false;

            // Disable input method editor to false so it doesnt start off in non english
            // Temporary solution until localization is added if ever...            
            InputMethod.SetIsInputMethodEnabled(
                this.cCommand,
                !Executioner.Config.GetBool("Command Box", "Disable Input Method", true)
            );

            // Style command input
            int width = Math.Max(200, Executioner.Config.GetInt("Command Box", "Width", 300));
            this.cCommand.MinWidth = width;

            // Max width
            int maxWidth = Executioner.Config.GetInt("Command Box", "Max Width", -1);
            int screenWidth = (int)SystemParameters.VirtualScreenWidth - 50 - (int)(this.ActualWidth - this.cCommand.ActualWidth);
            if (maxWidth == -1) {
                maxWidth = screenWidth;
            }
            else {
                maxWidth = maxWidth.MaxMin(width, screenWidth);
            }
            this.cCommand.MaxWidth = maxWidth;

            // Max height
            int maxHeight = Executioner.Config.GetInt("Command Box", "Max Height", -1);
            int screenHeight = (int)SystemParameters.VirtualScreenHeight - 134;
            if (maxHeight == -1) {
                maxHeight = screenHeight;
            }
            else {
                maxHeight = maxWidth.MaxMin(200, screenHeight);
            }
            this.cCommand.MaxHeight = maxHeight;

            // Taskbar
            if (Executioner.Config.GetBool("Command Box", "Show In Taskbar", PEnvironment.IsWindows7OrAbove)) {
                // In the future add jumplist support
                this._TaskbarMode = true;
                this.ShowInTaskbar = true;
                this.ResizeMode = ResizeMode.CanMinimize;
                // Set window state to minimized and then show the window.
                this.Hide();
                this.Visibility = Visibility.Visible;
                this.Topmost = Executioner.Config.GetBool("Command Box", "Top Most", false);                
            }
            else {
                this._TaskbarMode = false;
                this.ShowInTaskbar = false;
                this.ResizeMode = ResizeMode.NoResize;
                this.Hide();
                this.Topmost = true;
            }

            this.CallStrings = new List<string>();
            string callString = Executioner.Config.GetString("Command Box", "Call String", "cmdbox");
            this.CallStrings.Add(callString);
        }
        public void Unload() {
            // Intentionally left blank
        }
        #endregion        
        #region IConfigurable<IniFile>
        public IConfigurator<IniFile> Configurator {
            get {
                if (this._Configurator == null) {
                    this._Configurator = new CommandBoxConfigurator();
                }

                return this._Configurator;
            }
        }
        #endregion
    }
}
